---
title: RabbitMQ
sidebar_position: 0
---

## RabbitMQ 是什么

RabbitMQ 是一个实现了 高级消息队列协议(AMQP, Advanced Message Queuing Protocol)的开源中间件, 一般的用途就是在各个系统之间接收消息,分发消息

## 用了有什么好处

引入 RabbitMQ 大致可以有以下三个好处

### 解耦

系统各个模块之间总会需要数据传递, 以前的单体应用会将所有模块全都做在一起, 好处是系统内的通信畅通无阻, 但是对于后续的扩展比较麻烦

所以需要对业务进行拆分, 根据业务模块拆分出多个可以独立部署运行的子系统, 比如订单系统,配送系统,通知系统,客户信息系统等

假设配送完成之后, 需要从 `配送` 发送消息给 `订单` 更新订单状态, 还需要发给 `通知` 提醒用户配送完成, 这时候可以选择在`配送`中分别调用`订单`和`通知`的对应接口

乍一看没什么问题, 但业务总是会有变更的, 如果这时候出现一个第三方的系统, 也需要对接这个 **配送完成** 的消息, 那么就需要在 `配送` 中再加一次接口调用

这样的变更不止一处, 每个地方都这样处理就非常麻烦了, 所以可以通过某种配置动态进行调整

如果不考虑其他服务, 我们可以将地址写在类似 `appsettings.json` 这样的配置里, 这样只需要修改配置文件即可增减需要发送消息的地址

这种方式还是需要我们手动操作, 虽然省去了动代码的麻烦, 每次其它系统有业务变更还是需要做修改

此时就可以使用消息队列进行解耦

`配送` 只需要保证 **配送完成** 这个消息正常发送到消息队列即可, 至于有哪些系统需要使用这条消息, 就不是 `配送` 需要考虑的事情了

这样可以极大的简化各个系统之间的设计, 降低各系统之间的耦合

### 异步

以上一点为例, `配送` 直接调用 `订单` 和 `通知` 的接口

如果是以同步的方式调用, 除了执行 `配送` 自身业务的耗时以外, 还需要加上等待 `订单` 和 `通知` 两个系统执行完成的总耗时

如果采用异步的方式调用, 除了执行 `配送` 自身业务的耗时以外, 还需要加上等待 `订单` 和 `通知` 两个系统执行完成的最大耗时

若是两个系统中有任意一个调用失败, 即使该次 `配送` 业务执行成功了, 但也有可能会将自己的成功操作回滚

若是使用消息队列, `配送` 只需要保证自己的消息发送成功即可, `订单` 和 `通知` 的处理并不会有影响

### 削峰

以上上一点为例, `配送` 直接调用 `订单` 和 `通知` 的接口

如果并发数量极高, 一次性有一万个 **配送完成**, 然后就同时调用了一万次 `订单` 和 `通知` 接口, 此时可能会产生大量数据库io操作

会不会崩溃我不知道, 但是大概率会有阻塞

如果使用消息队列, 由于上一条的异步特性, `配送` 的操作只到发送消息就结束了, 可以直接给 前端/客户端 返回操作成功的提示, 不用陪着一起阻塞卡死

消息发送成功后可以由 `订单` 和 `通知` 自己决定如何处理这些消息, 不管是一次取一条一个一个处理, 亦或是一次取一千条批量处理, 总的数据库io操作也会比之前的方式少很多


## 如何部署

在这里只推荐使用docker部署, 不然需要装 erlang 环境, 太麻烦

```shell
docker run -itd -p 5672:5672 -p 15672:15672 --restart always --name rabbitmq rabbitmq:management
```

建议在实际部署的时候把端口换一下, 免得被人用默认端口攻击

最好设置一下默认的账号密码

```shell
docker run -itd \
    -p 5672:5672 \
    -p 15672:15672 \
    -e RABBITMQ_DEFAULT_USER=rabbitmq \
    -e RABBITMQ_DEFAULT_PASS=abc@123 \
    --restart always \
    --name rabbitmq \
    rabbitmq:management
```
